namespace Org.Loon.Framework.Xna.Game.Action.Collision
{

    using Org.Loon.Framework.Xna.Game.Core;
    using Org.Loon.Framework.Xna.Game.Core.Geom;
    using Org.Loon.Framework.Xna.Game.Utils;
    using Org.Loon.Framework.Xna.Java.Collections;
    using System.Collections.Generic;


    public class CollisionObject
    {

        internal class TempMatrix
        {

            public TempMatrix()
            {
                this.objects = new LinkedList();
            }

            public LinkedList objects;

        }

        public const int COLLISION_ONE = 0;

        public const int COLLISION_MATRIX = 1;

        private CollisionObject.TempMatrix[][] places;

        private List<LObject> objects;

        private int method;

        private int gridSize;

        private int width;

        private int height;

        public CollisionObject(List<LObject> os)
        {
            this.method = 0;
            this.gridSize = 0;
            this.width = 0;
            this.height = 0;
            this.objects = os;
            this.method = 0;
        }

        public CollisionObject(List<LObject> os, int gs)
            : this(os, gs, LSystem.screenRect.width, LSystem.screenRect.height)
        {

        }

        public CollisionObject(List<LObject> os, int gs, int w,
                int h)
        {
            this.method = 0;
            this.width = 0;
            this.height = 0;
            this.method = 1;
            this.objects = os;
            this.gridSize = gs;
            this.width = w;
            this.height = h;
            this.UpdateMatrix(w, h);
        }

        public void Register(LObject o)
        {
            lock (objects)
            {
                objects.Add(o);
            }
        }

        public Dictionary<LObject, LObject> RunCollisionEngineForCollisions(
                float mapXPosition, float mapYPosition, float xOffset,
                float yOffset, bool checkNearBy)
        {
            Dictionary<LObject, LObject> collisionOccurrence = new Dictionary<LObject, LObject>();

            foreach (LObject currentSprite in objects)
            {

                foreach (LObject conflictingSprite in objects)
                {
                    if (currentSprite != conflictingSprite)
                    {
                        if (SpritesOverlap(currentSprite, conflictingSprite,
                                mapXPosition, mapYPosition, xOffset, yOffset,
                                checkNearBy))
                        {
                            collisionOccurrence.Add(currentSprite,
                                    conflictingSprite);
                        }
                    }
                }
            }
            return collisionOccurrence;
        }

        private bool SpritesOverlap(LObject currentSprite,
                LObject conflictingSprite, float mapXPosition, float mapYPosition,
                float xOffset, float yOffset, bool checkNearBy)
        {
            float enlargement = (checkNearBy) ? 10.0f : 0.0f;
            RectBox currentSpriteShape = new RectBox(GetAbsoluteXPosition(
                    currentSprite, mapXPosition, xOffset), GetAbsoluteYPosition(
                    currentSprite, mapYPosition, yOffset), currentSprite.GetWidth()
                    + enlargement, currentSprite.GetHeight() + enlargement);
            RectBox conflictingSpriteShape = new RectBox(GetAbsoluteXPosition(
                    conflictingSprite, mapXPosition, 0), GetAbsoluteYPosition(
                    conflictingSprite, mapYPosition, 0),
                    conflictingSprite.GetWidth() + enlargement,
                    conflictingSprite.GetHeight() + enlargement);
            return currentSpriteShape.Intersects(conflictingSpriteShape);
        }

        private float GetAbsoluteYPosition(LObject currentSprite,
                float mapYPosition, float yOffset)
        {
            return currentSprite.GetY() + MathUtils.Abs(mapYPosition) + yOffset;
        }

        private float GetAbsoluteXPosition(LObject currentSprite,
                float mapXPosition, float xOffset)
        {
            return currentSprite.GetX() + MathUtils.Abs(mapXPosition) + xOffset;
        }

        public List<LObject> GetSprites()
        {
            return objects;
        }

        private void UpdateMatrix(int width_0, int height_1)
        {
            this.places = (CollisionObject.TempMatrix[][])CollectionUtils.XNA_CreateJaggedArray(typeof(CollisionObject.TempMatrix), width_0, height_1);
            for (int y = 0; y < height_1; y++)
            {
                for (int x = 0; x < width_0; x++)
                {
                    this.places[x][y] = new CollisionObject.TempMatrix();
                }
            }
        }

        public LObject FindCollision(int x, int y, int layer)
        {
            for (int i = 0; i < this.objects.Count; i++)
            {
                LObject obj = (LObject)this.objects[i];
                if (obj.GetLayer() == layer)
                {
                    if (obj.GetCollisionArea() != null
                            && obj.GetCollisionArea().Contains(x, y))
                    {
                        return obj;
                    }
                }
            }
            return null;
        }

        public LObject FindCollision(RectBox rect, int layer)
        {
            if (this.method == COLLISION_ONE)
            {
                for (int i = 0; i < this.objects.Count; i++)
                {
                    LObject obj = (LObject)this.objects[i];
                    if ((obj.GetLayer() == layer)
                            && (obj.GetCollisionArea().Intersects(rect)))
                    {
                        return obj;
                    }
                }
            }
            if (this.method == COLLISION_MATRIX)
            {
                for (int y = rect.Y() / this.gridSize; y < (rect.y + rect.height)
                        / this.gridSize + 1; y++)
                {
                    for (int x = rect.X() / this.gridSize; x < (rect.x + rect.width)
                            / this.gridSize + 1; x++)
                    {
                        if ((x < this.width) && (y < this.height))
                        {
                            for (int i_0 = 0; i_0 < this.places[x][y].objects.Count; i_0++)
                            {
                                LObject res = (LObject)this.places[x][y].objects[i_0];
                                if ((res.GetLayer() == layer)
                                        && (rect.Intersects(res.GetCollisionArea())))
                                {
                                    return res;
                                }
                            }
                        }
                    }
                }

            }

            return null;
        }

        public LObject FindCollision(RectBox rect, string ModelName, int layer)
        {
            if (this.method == COLLISION_ONE)
            {
                for (int i = 0; i < this.objects.Count; i++)
                {
                    LObject obj = (LObject)this.objects[i];
                    if (obj.GetName() == null)
                    {
                        continue;
                    }
                    if ((obj.GetLayer() == layer)
                            && (obj.GetName().Equals(ModelName))
                            && (obj.GetCollisionArea().Intersects(rect)))
                    {
                        return obj;
                    }
                }
            }

            if (this.method == COLLISION_MATRIX)
            {
                for (int y = rect.Y() / this.gridSize; y < (rect.y + rect.height)
                        / this.gridSize + 1; y++)
                {
                    for (int x = rect.X() / this.gridSize; x < (rect.x + rect.width)
                            / this.gridSize + 1; x++)
                    {
                        if ((x < this.width) && (y < this.height))
                        {
                            for (int i_0 = 0; i_0 < this.places[x][y].objects.Count; i_0++)
                            {
                                LObject res = (LObject)this.places[x][y].objects[i_0];
                                if (res.GetName() == null)
                                {
                                    continue;
                                }
                                if ((res.GetLayer() == layer)
                                        && (rect.Intersects(res.GetCollisionArea()))
                                        && (res.GetName().Equals(ModelName)))
                                {
                                    return res;
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }

        public LObject FindCollision(LObject obj0, int layer)
        {
            if (this.method == COLLISION_ONE)
            {
                for (int i = 0; i < this.objects.Count; i++)
                {
                    LObject obj = (LObject)this.objects[i];
                    if ((obj.GetLayer() == layer)
                            && (obj0 != obj)
                            && (obj.GetCollisionArea().Intersects(obj0
                                    .GetCollisionArea())))
                    {
                        return obj;
                    }
                }
            }

            if (this.method == COLLISION_MATRIX)
            {
                RectBox rect = obj0.GetCollisionArea();
                for (int y = rect.Y() / this.gridSize; y < (rect.y + rect.height)
                        / this.gridSize + 1; y++)
                {
                    for (int x = rect.X() / this.gridSize; x < (rect.x + rect.width)
                            / this.gridSize + 1; x++)
                    {
                        if ((x < this.width) && (y < this.height))
                        {
                            for (int i_0 = 0; i_0 < this.places[x][y].objects.Count; i_0++)
                            {
                                LObject o = (LObject)this.places[x][y].objects[i_0];
                                if ((o.GetLayer() == layer)
                                        && (obj0 != o)
                                        && (o.GetCollisionArea()
                                                .Intersects(obj0
                                                        .GetCollisionArea())))
                                {
                                    return o;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

        public LObject FindCollision(LObject obj0, string name, int layer)
        {
            if (this.method == COLLISION_ONE)
            {
                for (int i = 0; i < this.objects.Count; i++)
                {
                    LObject obj = (LObject)this.objects[i];
                    if (obj.GetName() == null)
                    {
                        continue;
                    }
                    if ((obj.GetLayer() == layer)
                            && (obj0 != obj)
                            && (obj.GetName().Equals(name))
                            && (obj.GetCollisionArea().Intersects(obj0
                                    .GetCollisionArea())))
                    {
                        return obj;
                    }
                }
            }

            if (this.method == COLLISION_MATRIX)
            {
                RectBox rect = obj0.GetCollisionArea();
                for (int y = rect.Y() / this.gridSize; y < (rect.y + rect.height)
                        / this.gridSize + 1; y++)
                {
                    for (int x = rect.X() / this.gridSize; x < (rect.x + rect.width)
                            / this.gridSize + 1; x++)
                    {
                        if ((x < this.width) && (y < this.height))
                        {
                            for (int i_0 = 0; i_0 < this.places[x][y].objects.Count; i_0++)
                            {
                                LObject o = (LObject)this.places[x][y].objects[i_0];
                                if (o.GetName() == null)
                                {
                                    continue;
                                }
                                if ((o.GetLayer() == layer)
                                        && (obj0 != o)
                                        && (o.GetName().Equals(name))
                                        && (o.GetCollisionArea()
                                                .Intersects(obj0
                                                        .GetCollisionArea())))
                                {
                                    return o;
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }

        public bool FindCollision(LObject src, LObject obj, int layer)
        {
            return (src.GetLayer() == layer) && (obj.GetLayer() == layer)
                    && (src.GetCollisionArea().Intersects(obj.GetCollisionArea()));
        }

        public void Clear()
        {
            lock (objects)
            {
                objects.Clear();
            }
        }

    }
}
